﻿using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
using Automator.Tasks.Core;
using Automator.Tasks.Windows;

namespace Automator.Tasks
{
    /// <summary>
    /// Class for launching executable file.
    /// Defined attributes:
    /// ExeName: specifies the name of executable file with full path
    /// Arguments: command line arguments for exe-file
    /// Wait: boolean attribute, whether workflow execution should wait for executable file to finish its work
    /// </summary>
    public class CallTask: Task, ITaskExecutable
    {       
        #region ITaskExecutable Members

        public void Execute(WorkflowExecutionContext context)
        {
            Thread t = new Thread(new ParameterizedThreadStart(ExecuteProcess));
            t.Start(new TaskThreadingContext(this, context));
            t.Join();
            if (ThreadException != null)
                throw new TaskExecutionException(ThreadException.Message, ThreadException);
        }

        #endregion
        
        /// <summary>
        /// Field for catch an exception in a thread
        /// </summary>
        private static Exception ThreadException;
        
        /// <summary>
        /// Sync object
        /// </summary>
        private static object locker = new object();

        public CallTask()
            : base()
        {
            this.Title = "Call";
            this.Description = "Run executable file";
            this.TaskImage = new BitmapImage(new Uri("/Automator.Tasks;component/Resources/executable.png", UriKind.Relative));

            this.Attributes.Add(new TaskAttributeDefinition() { Key = "ExeName", Value = String.Empty });
            this.Attributes.Add(new TaskAttributeDefinition() { Key = "Arguments", Value = String.Empty });
            this.Attributes.Add(new TaskAttributeDefinition() { Key = "Wait", Value = true });
        }

        public override string CommandText
        {
            get
            {
                return String.Format("{0} {1}", Attributes["ExeName"].Value.ToString().Trim(),
                                     Attributes["Arguments"].Value.ToString().Trim()).Trim();
            }
            set { base.CommandText = value; }
        }
        
        private void ExecuteProcess(object arg)
        {
            lock(locker)
            {
                try
                {
                    CallTask task = (CallTask)(arg as TaskThreadingContext).Task;
                    WorkflowExecutionContext context = (arg as TaskThreadingContext).ExecutionContext;
                    Process p = new Process();
                    p.EnableRaisingEvents = true;
                    p.StartInfo.Arguments = context.DereferenceVariables(task.Attributes["Arguments"].Value);
                    p.StartInfo.CreateNoWindow = false;
                    p.StartInfo.FileName = context.DereferenceVariables(task.Attributes["ExeName"].Value);
                    p.StartInfo.UseShellExecute = true;
                    p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
                    p.StartInfo.WorkingDirectory = Path.GetDirectoryName(p.StartInfo.FileName);
                    p.Start();
                    if (Convert.ToBoolean(task.Attributes["Wait"].Value))
                        p.WaitForExit();
                    ThreadException = null;
                }
                catch (Exception ex)
                {
                    ThreadException = ex;
                }
            }
        }

        public override bool EditTask()
        {
            base.EditTask();
            CallTaskEditWindow window = new CallTaskEditWindow();
            window.Owner = Application.Current.MainWindow;
            window.Title = String.Format("Edit {0} Task", this.Title);
            //performing binding to the header
            window.header.ContentPanel.DataContext = this;

            window.edtExeFile.Text = this.Attributes["ExeName"].Value.ToString();
            window.edtArguments.Text = this.Attributes["Arguments"].Value.ToString();
            window.chkWait.IsChecked = Convert.ToBoolean(this.Attributes["Wait"].Value);
            window.footer.BtnOK.Click += delegate { window.DialogResult = true; };

            if (window.ShowDialog() == true)
            {
                this.Attributes["ExeName"].Value = window.edtExeFile.Text.Trim();
                this.Attributes["Arguments"].Value = window.edtArguments.Text.Trim();
                this.Attributes["Wait"].Value = window.chkWait.IsChecked;
                this.CommandText = String.Empty;
                return true;
            }
            else return false;
        }
    }
}
